<?php
/**
 *
 * @author cinemas
 * @since v1.0
 * @modify 2018.6.10
 * @copyright 深圳亿游
 */
error_reporting(E_NOTICE);
require_once(LIB_PATH . 'controller/root.con.php');
require_once(LIB_PATH . '/spider/myspider.php');
require_once ROOT_PATH . "lib/weixinpay/lib/WxPay.Config.php";
require_once ROOT_PATH . "lib/weixinpay/lib/WxPay.Api.php";
require_once ROOT_PATH . "lib/weixinpay/lib/WxPay.Data.php";
require_once ROOT_PATH . "lib/weixinpay/lib/WxPay.Exception.php";
require_once ROOT_PATH . "lib/weixinpay/lib/WxPay.Notify.php";
require_once ROOT_PATH . "lib/weixinpay/lib/NativePay.php";
require_once ROOT_PATH . 'lib/weixinpay/example/log.php';
require_once ROOT_PATH . "lib/weixinpay/example/WxPay.JsApiPay.php";

//支付完成以后通知类
class PayNotifyCallBack extends WxPayNotify
{
	public function Queryorder($transaction_id)
	{
		$input = new WxPayOrderQuery();
		$input->SetTransaction_id($transaction_id);
		$result = WxPayApi::orderQuery($input);
		Log::DEBUG("query:" . json_encode($result));
		if (array_key_exists("return_code", $result)
			&& array_key_exists("result_code", $result)
			&& $result["return_code"] == "SUCCESS"
			&& $result["result_code"] == "SUCCESS") {//更新订单的状态
			OrderExt::finishByResult($result);
			Log::DEBUG("====call back out_trade_no=:" . $result['out_trade_no'] . ' orderId=' . $orderId . ' shopId=' . $shopId);
			return true;
		}
		return false;
	}
	
	//重写回调处理函数
	public function NotifyProcess($data, &$msg)
	{
		Log::DEBUG("call back:" . json_encode($data));
		$notfiyOutput = array();
		
		if (!array_key_exists("transaction_id", $data)) {
			$msg = "输入参数不正确";
			return false;
		}
		//查询订单，判断订单真实性
		if (!$this->Queryorder($data["transaction_id"])) {
			$msg = "订单查询失败";
			return false;
		}
		return true;
	}
	
}

class orderCon extends rootCon
{

	
	public function notifyAction()
	{
		//初始化日志
		$logHandler = new CLogFileHandler(ROOT_PATH . "/log/" . date('Y-m-d') . '.log');
		$log = Log::Init($logHandler, 15);
		Log::DEBUG("begin notify");
		$notify = new PayNotifyCallBack();
		$notify->Handle(false);
	}
	
	public function statusAction()
	{
		$uid = mylogin::getUid(true);
		$order = new Order();
		$order->find(r_int('orderId'));
		if ($order->buyerUid != $uid) {
			$this->j(-2, '您无权查看此订单');
		}
		
		if ($order->buyerPay > 0) {
			$this->j(0, 'done', ['status' => 66]);
		} else {
			$this->j(0, 'doing', ['status' => $order->status]);
		}
	}
	
	public function listAction()
	{
		$uid = mylogin::getUid(true);
		NoteExt::readAllOrder($uid);
		$order = new Order();
		$order->load();
		$order->buyerUid = $uid;
		// $order->orderType = ORDER_TYPE_BUY;//1交易 2打赏
		$con = $order->getConByLoad();
		$con .= ' AND orderType in('.ORDER_TYPE_BUY.','.ORDER_TYPE_CROWD.')';
		$sql = 'SELECT * FROM tbl_order  WHERE  ' . $con;
		// echo $sql;die;
		$rect = $order->pager($sql);
		$this->j(0, '订单列表', $rect);
	}
	
	//查询订单详情
	public function infoAction()
	{
		$uid = mylogin::getUid(true);
		$orderId = r_int('orderId');
		if (!$orderId) {
			$this->j(-1, '订单号错误', $orderId);
		}
		
		$order = new Order();
		$order->find(r_int('orderId'));
		if ($order->buyerUid != $uid) {
			$this->j(-2, '您无权查看此订单');
		}
		
		$user = new User();
		$user->find($uid);
		$order->arr['leftGold'] = $user->gold;
		$order->arr['leftScore'] = $user->score;
		
		$this->j(0, '订单完成', $order->tidy());
		
	}
	
	
	//获取打折价格
	private function getPromotionInCents($promotionId, $uid, $oldPrice)
	{
		if (!$promotionId) {
			return 0;
		}
		$promotion = new Promotion();
		$promotion->find($promotionId);
		if ($promotion->uid != $uid) {
			$this->j(-8, '您不能使用他人的优惠券');
		}
		
		if ($promotion->expire < date('Y-m-d H:i:s')) {
			$this->j(-10, '您的优惠券已经过期');
		}
		
		if ($promotion->status != 0) {
			$this->j(-9, '您的优惠券已使用或者已经过期');
		}
		
		if ($promotion->limitPrice > $oldPrice) {
			$this->j(-7, '您的优惠券必须满' . $promotion->limitPrice . "元才能使用", ['orderPrice' => $oldPrice]);
		}
		
		$cents = $promotion->discountPrice * 100;
		
		//检查@todo 检查折扣券是否可以使用
		return $cents;
	}
	
	private function addSpam($uid)
	{
		$currentCount = $this->getSpamCount($uid);
		if ($currentCount < 1) {
			myredis::set("ORDER_SPAM" . $uid, 0, 60 * 15);
		}
		return myredis::increment("ORDER_SPAM" . $uid);
	}
	
	private function getSpamCount($uid)
	{
		return intval(myredis::get("ORDER_SPAM" . $uid));
	}
	
	private function isSpam($uid)
	{
		$currentCount = $this->addSpam($uid);
		if ($currentCount > 10) {//最多10个订单未支付
			return true;
		} else {
			return false;
		}
	}
	
	//下订单
	public function addAction()
	{//生成订单
		$uid = mylogin::getUid(true);
		if ($this->isSpam($uid)) {
			$this->j(-8, '请先到个人中心待支付订单中完成支付');
		}
		
		$order = new Order();
		$order->load();
		
		$course = new Course();
		$courseId = r_int('courseId');
		$find = $course->find([['courseId', $courseId], ['status', STATUS_PUBLISH]]);
		if (!$find) {
			$this->j(-1, '该课程已经下架');
		}
		
		$shouldPayInCents = intval($course->price * 100);
		$order->goodsPrice = $course->oldPrice;//商品原始价格
		$order->unitPrice = $course->price;//商品单价
		$remark = '';
		$activeId = r_int('active_id');
		$activeType = r('active_type');
		if($activeId && $activeType) {
			switch ($activeType) {
				case 'crowdfunding':
					//众筹
					$sql = 'SELECT * FROM tbl_course_crowdfunding  WHERE  course_id = '.$courseId.' and id = '.$activeId;
					$active = $course->query($sql);
					if(!$active) {
						$this->j(-1, '活动不存在');
					}
					$active = $active[0];
					if($active['status'] != 1 || $active['end_time'] < time() || $active['number_real'] >= $active['number_total']) {
						$this->j(-1, '活动已结束');
					}
					
					if($active['start_time'] > time()) {
						$this->j(-1, '活动未开始');
					}
					
					
					$shouldPayInCents = intval($active['deposit'] * 100);
					$remark = '众筹活动订金：'.$active['deposit'].'元';
					$order->active_id = $activeId;
					$order->orderType = 4;
					$order->goodsPrice = $course->price;
					$order->unitPrice = $active['deposit'];
					break;
				default:
					$this->j(-1, '活动类型不存在');
			}
		}
		
		$order->schoolId = $course->schoolId;
		
		$school = new School();
		$school->find($course->schoolId);
		$order->location = $school->addr ? $school->addr : $school->location;
		$order->arr['schoolName'] = $school->schoolName;
		$order->arr['distance'] = $school->schoolName;//定位，这里是因为订单前端的错误
		
		$order->courseLogoUrl = $course->uploadImg;
		$order->buyerShouldPay = $shouldPayInCents / 100;
		$order->buyerUid = $uid;
		$order->status = STATUS_SUBMIT;
		$order->created = date('Y-m-d H:i:s');
		
		$order->title = $course->courseName;
		$order->ip = myrequest::getIP();
		$order->remark = $remark;
		$order->transaction_id = '';
		
		$orderSaved = $order->save();
		
		if (!$orderSaved) {
			$this->j(-5, '订单保存失败,请稍后再试！');
		}
		NoteExt::unreadOneOrder($uid);
		$order->hide();
		
		$user = new User();
		$user->find($uid);
		$order->arr['leftGold'] = $user->gold;
		$order->arr['leftScore'] = $user->score;
		
		$this->j(0, '', $order->arr);
	}
	
	//如果订单为0元，则调用这个接口
	/*public function finishAction(){
		$orderId = r_int('orderId');
		$uid = mylogin::getUid(true);
		$promotionId   = r_int('promotionId');
		if(!$promotionId) $this->j(-10,'请选择代金券或抵扣券');

		$order = new Order();
		$order->find($orderId);

		$filmSession = new FilmSession();
		$filmSession->find($order->filmSessionId);
		$promotionInCents = $this->getPromotionInCents($promotionId,$uid,$filmSession);

		if($promotionInCents){//抵扣券
			$shouldPayInCents = $order->ticketCount  * $filmSession->priceInCents - $promotionInCents;
		}

		if($shouldPayInCents >0){
			$this->j(-1,'您还需要支付'.($shouldPayInCents/100).'元!');
		}

		$order->buyerPay = 0;//0元支付
		$order->status = STATUS_BUYER_PAID;
		$order->payTime = date('Y-m-d H:i:s');

		if(PromotionExt::usePromotion($promotionId)){
			$order->promotionId = $promotionId;
			$order->save();//调用api前第一次保存
		}else{
			$this->j(-12,'发生错误，无法使用当前优惠券!',['promotionId'=>$promotionId]);
		}

		NoteExt::unreadOneOrder($uid);//提醒
		$this->j(0,'支付完成!');
	}*/
	
	
	//优惠券的统一下单，并返回sign
	public function promotionAction()
	{
		$promotionConfigId = r_int('promotionConfigId');
		$uid = mylogin::getUid(true);
		
		$getTime = PromotionExt::isUserGet($uid, $promotionConfigId);
		if (!$getTime) {
			$this->j(-3, '您没有秒杀到该优惠券');
		} else {
			if ((time() - $getTime) > PROMOTION_PAY_TIMEOUT) {
				PromotionExt::release($uid, $promotionConfigId);
				$this->j(-9, '您的秒杀券已经超过支付时间限制了，请重新参与秒杀！');
			}
		}
		if (PromotionExt::isPayFinish($uid, $promotionConfigId)) {
			$this->j(-5, '您已经成功抢票,请到个人中心查看优惠券');
		}
		
		
		//@todo 从内存中获取openid
		$user = new User();
		$find = $user->find($uid);
		if (!$find) {
			$this->j(-1, '天呐，系统居然出错了！');
		}
		$openId = $user->openId;
		
		$promotion = PromotionExt::get($promotionConfigId);
		$myOrder = new Order();
		
		$myOrder->buyerShouldPay = $promotion['price'];
		$myOrder->buyerTradeNo = $promotionConfigId . '--' . $uid . '--' . time();
		
		
		$wxOrder = $this->unifiedOrder($myOrder, $openId, PROMOTION_PAY_TIMEOUT);//微信统一下单
		
		if (!($wxOrder['return_code'] == 'SUCCESS' || $wxOrder['result_code'] == 'SUCCESS' || $wxOrder['return_msg'] == 'OK')) {
			$this->j(-2, "天呐，系统出错了", $wxOrder);
		}
		
		//--------生成sign-----------
		$timeStamp = time();
		$rect['uid'] = $user->uid;
		$rect['nonceStr'] = $wxOrder['nonce_str'];
		$rect['package'] = 'prepay_id=' . $wxOrder['prepay_id'];
		$rect['signType'] = "MD5";//HMAC-SHA256 ,仅仅支持这两种，需要和下单时保持一致
		$rect['timeStamp'] = "$timeStamp";
		$srcKey = "appId=" . WEIXIN_APPID . "&nonceStr={$rect['nonceStr']}&package={$rect['package']}&signType={$rect['signType']}&timeStamp={$rect['timeStamp']}&key=" . WEIXIN_MCHID_KEY;
		$rect['paySign'] = md5($srcKey);
		$this->j(0, "sign", $rect);
	}
	
	//小程序的统一下单，并返回sign
	public function signAction()
	{
		$uid = mylogin::getUid(true);
		$user = new User();
		$find = $user->find($uid);
		if (!$find) {
			$this->j(-1, '天呐，系统居然出错了！');
		}
		$openId = $user->openId;
		
		$order = new Order();
		$order->load();
		$order->score = r('score');
		if ($order->score > $user->score) {
			$this->j(-1, "积分不足");
		}
		
		$order->gold = r('gold');
		if ($order->gold > $user->gold) {
			$this->j(-1, "金币不足");
		}
		
		$promotionId = r_int('promotionId');
		
		//打赏
		if (r_int('orderType') == ORDER_TYPE_LIKE) {
			$order->orderType = ORDER_TYPE_LIKE;
			$order->courseId = 0;
			$order->buyerUid = $uid;
			$order->teacherId = r_int('teacherId');
			$order->buyerShouldPay = r('price');
			$order->goodsCount = 1;
			$order->unitPrice = $order->buyerShouldPay;
			$order->title = "打赏";
			$order->buyerTradeNo = '0' . '--' . $uid . '--' . time();
			$order->ip = myrequest::getIP();
			$order->save();//新生成订单必须更新orderId
			$promotionId = 0;//不能用金币或者优惠券等进行打赏,只能用现金
		} else {
			if (r_int('orderType') == ORDER_TYPE_FEE) {//续费订单
				$order->orderType = ORDER_TYPE_FEE;
				$order->courseId = 0;
				$order->buyerUid = $uid;
				$order->schoolId = r_int('schoolId');
				//$order->buyerShouldPay =  r('price');
				$feeId = r_int('feeId');
				$order->location = $feeId;//找个地方存放费用ID
				$fee = new Fee();
				$fee->find($feeId);
				//if($order->buyerShouldPay != $fee->price){
				//$this->j(-1,"订单价格错误",['price'=>$order->buyerShouldPay,'priceInDB'=>$fee->price]);
				$order->buyerShouldPay = $fee->price;
				//}
				
				$order->goodsCount = 1;
				$order->unitPrice = $order->buyerShouldPay;
				
				
				$order->title = "续费:" . $fee->title;
				$order->buyerTradeNo = '0' . '--' . $uid . '--' . time();
				$order->ip = myrequest::getIP();
				$order->save();//新生成订单必须更新orderId
				$promotionId = 0;//不能用金币或者优惠券等进行打赏,只能用现金
			}
		}
		
		$number = r_int('goodsCount');
		
		$myOrder = $this->getMyOrder($order->orderId, $promotionId, $number);
		if ($myOrder->orderType == ORDER_TYPE_BUY || $myOrder->orderType == ORDER_TYPE_CROWD) {//购买课程订单,应该支付费用为0的情况
			if ($myOrder->buyerShouldPay == 0) {
				OrderExt::finishCourse($myOrder, 0);
				$this->j(88, "支付费用为0", ['orderId' => $myOrder->orderId, 'buyerShouldPay' => 0]);
			}
		}
		
		
		$wxOrder = $this->unifiedOrder($myOrder, $openId);//微信统一下单
		
		if (!($wxOrder['return_code'] == 'SUCCESS' || $wxOrder['result_code'] == 'SUCCESS' || $wxOrder['return_msg'] == 'OK')) {
			$this->j(-2, "天呐，系统出错了", $wxOrder);
		}
		
		//https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=9_1&index=1
		//https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/template-message.html
		//----更新prepay_id用来发模板消息----
		$msgKey = new MessageKey();
		$msgKey->messageKey = $wxOrder['prepay_id'];
		$msgKey->uid = $uid;
		$msgKey->keyType = 1;//订单交易1 提交表单2
		$msgKey->orderId = $order->orderId;
		$msgKey->save();
		
		//------------------------------------生成sign---------------------------------
		$timeStamp = time();
		$rect['uid'] = $user->uid;
		$rect['nonceStr'] = $wxOrder['nonce_str'];
		$rect['package'] = 'prepay_id=' . $wxOrder['prepay_id'];
		$rect['signType'] = "MD5";//HMAC-SHA256 ,仅仅支持这两种，需要和下单时保持一致
		$rect['timeStamp'] = "$timeStamp";
		$srcKey = "appId=" . WEIXIN_APPID . "&nonceStr={$rect['nonceStr']}&package={$rect['package']}&signType={$rect['signType']}&timeStamp={$rect['timeStamp']}&key=" . WEIXIN_MCHID_KEY;
		$rect['paySign'] = md5($srcKey);
		$this->j(0, "sign", $rect);
	}
	
	private function unifiedOrder($myOrder, $openId, $timeoutSeconds = 600)
	{
		$newTradeNo = $myOrder->buyerTradeNo;
		$shouldPayCents = round($myOrder->buyerShouldPay * 100);
		if ($shouldPayCents < 0) {
			$shouldPayCents = 0;
		}
		
		if ($myOrder->orderType == ORDER_TYPE_BUY || $myOrder->orderType == ORDER_TYPE_CROWD) {//购买课程订单,应该支付费用为0的情况
			if ($myOrder->buyerShouldPay == 0) {
				OrderExt::finishCourse($myOrder, 0);
				$this->j(88, "支付费用为0", ['orderId' => $myOrder->orderId, 'buyerShouldPay' => 0]);
			}
		}
		
		if (!$shouldPayCents) {
			$this->j(-20, '待支付金额为0，无法发起微信支付!');
		}
		
		$input = new WxPayUnifiedOrder();
		$input->SetBody("要培训");
		$input->SetAttach("要培训");
		$input->SetOut_trade_no($newTradeNo);
		$input->SetTotal_fee($shouldPayCents);
		$input->SetTime_start(date("YmdHis"));
		$input->SetTime_expire(date("YmdHis", time() + $timeoutSeconds));
		$input->SetGoods_tag("要培训");
		$input->SetNotify_url(WECHAT_NOTIFY_URL);//设置微信的通知回调地址
		$input->SetTrade_type("JSAPI");
		$input->SetOpenid($openId);
		$wxOrder = WxPayApi::unifiedOrder($input);//微信的订单
		return $wxOrder;
	}
	
	private function getMyOrder($orderId, $promotionId, $number = 1)
	{
		$uid = mylogin::getUid(true);
		$myOrder = new Order();//我们的订单
		$myOrder->find($orderId);//@todo 检查是否已经支付
		
		$myOrder->goodsCount = $number;
		
		if ($myOrder->buyerShouldPay < 0) {
			$this->j(-1, '支付金额不能小于0');
		}
		
		if (property_exists($myOrder, 'sellerShopId')) {
			$shopId = $myOrder->sellerShopId;
		} else {
			$shopId = SYSTEM_SHOP_ID;//系统内置的id
		}
		$myOrder->buyerTradeNo = $shopId . '--' . $orderId . '--' . time();//避免重复支付
		
		
		$serverPrice = $myOrder->unitPrice * $myOrder->goodsCount;//使用优惠券之前的价格,服务器端计算出的总价
		$promotionInCents = $this->getPromotionInCents($promotionId, $uid, $serverPrice);
		if ($promotionInCents) {
			$myOrder->promotionId = $promotionId;
			$myOrder->promotion = $promotionInCents / 100;
			$serverPrice -= $myOrder->promotion;
		}
		
		if (r('gold') || r('score')) {//金币或者积分
			$user = new User();
			$user->find($uid);
			
			if (r('score') && $user->score >= r('score')) {
				$serverPrice -= r('score') / 100;//积分是分
				$myOrder->score = r('score');
				$myOrder->useScore = 1;
			}
			
			if (r('gold') && $user->gold >= r('gold')) {
				$serverPrice -= r('gold');//金币yuan
				$myOrder->gold = r('gold');
				$myOrder->useGold = 1;
			}
		}
		
		$myOrder->buyerShouldPay = $serverPrice;
		
		if ($myOrder->buyerShouldPay < 0) {
			$myOrder->buyerShouldPay = 0;
		}
		
		$myOrder->save();
		return $myOrder;
	}
	
	//2.9 取消订单
	public function cancelAction()
	{
		$orderId = r_int('orderId');
		$order = new Order();
		$order->find($orderId);
		if ($order->buyerUid != mylogin::getUid(true)) {
			$this->j(-1, '这不是您的订单！');
		}
		
		$session = new FilmSession();
		$session->find($order->filmSessionId);
		if (date('Y-m-d H:i:s', time() - CANCEL_ORDER_TIME) > $session->showTime) {
			$this->j(-2, '已过申请退票时间！');
		}
		
		$order->status = STATUS_BUYER_CANCEL;
		$order->updateat = date('Y-m-d H:i:s');
		$orderSaved = $order->save();
		
		$orderInfo['UserSessionId'] = "$orderId";
		$orderInfo['OptionalClientClass'] = 'RSP';
		$orderInfo['OptionalClientId'] = '120.0.221.1';
		$orderInfo['OptionalClientName'] = 'MJYX';
		$result = FilmUtil::cancelOrder($orderInfo);
		$resultApi = $result->Result;
		if ($resultApi != 0) {
			mylog::write("---order---- cancelOrder error:" . json_encode($resultApi));
		}
		
		if ($orderSaved) {
			$resultApi = $this->refund($orderId);
			if ($resultApi != 0) {
				mylog::write("---order---- refund error:" . json_encode($resultApi));
			}
			
			$this->j(0, '已经提交退票申请');
		} else {
			$this->j(-3, '未成功提交退票申请，请稍后再试！');
		}
	}
}

